package com.maochang.config;

import com.alibaba.druid.pool.DruidDataSource;
import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import lombok.SneakyThrows;
import org.apache.ibatis.session.AutoMappingBehavior;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.TransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.sql.DataSource;
import java.util.ResourceBundle;

@Configuration //配置类
//@MapperScan 扫描接口  生成接口实现类  放到 容器中      //sql 会话 引用    bean   工厂的类引用的是那个会话
@MapperScan(basePackages = "com.maochang.mapper",sqlSessionFactoryRef ="sqlSessionFactoryBean")
//把业务类变成对象
@ComponentScan(basePackages ={"com.maochang.config.etc","com.maochang.service"}) //<mvc:annotation-driven>
@EnableTransactionManagement  //启注解事务管理，等同于xml配置方式的 <tx:annotation-driven />
public class spring {
    //1.资源绑定器
    ResourceBundle bundle=ResourceBundle.getBundle("db");
    //2.spring 加载配置文件   模式 Resolve 处理器
    @Bean
    public PathMatchingResourcePatternResolver patternResolver(){
        PathMatchingResourcePatternResolver patternResolver=new PathMatchingResourcePatternResolver();
        return  patternResolver;  //作用 加载配置文件
    }
    //3.配置数据源   连接池就是数据源
    @Bean
    public DataSource dataSource(){
        DruidDataSource dataSource=new DruidDataSource();
        dataSource.setUsername(bundle.getString("jdbc.username"));
        dataSource.setPassword(bundle.getString("jdbc.password"));
        dataSource.setUrl(bundle.getString("jdbc.url"));
        dataSource.setDriverClassName(bundle.getString("jdbc.driver"));
        return  dataSource;
    }
    //4.spring 来加载 mybatis   SqlSessionFactoryBean mybatis 的启动类
    @SneakyThrows
    @Bean(value = "sqlSessionFactoryBean")
    public MybatisSqlSessionFactoryBean aa(){
        MybatisSqlSessionFactoryBean sqlSf=new MybatisSqlSessionFactoryBean(); //  @MapperScan
        sqlSf.setTypeAliasesPackage("com.maochang.pojo"); //别名
        //sqlSf.setConfigLocation(patternResolver().getResource("classpath:MyBatis-config.xml"));//加载mybatis 配置文件
        sqlSf.setConfiguration(configuration());//加载mybatis 配置文件
        //mapper映射文件
        sqlSf.setMapperLocations(patternResolver().getResources("classpath:mapper/*.xml")); //配置映射
        //数据源
        sqlSf.setDataSource(dataSource());
        //分页功能
        sqlSf.setPlugins(mybatisPlusInterceptor());
        return sqlSf;
    }
    //5.废弃  Mybatis 配置文件
    public MybatisConfiguration configuration(){
        MybatisConfiguration cfg=new MybatisConfiguration();
        cfg.setAutoMappingBehavior(AutoMappingBehavior.FULL);//复杂结果集映射
        cfg.setMapUnderscoreToCamelCase(false);// 驼峰映射
        cfg.setUseGeneratedKeys(true);//设置回写
        return  cfg;
    }
    //6.事务配置   事务管理器
    @Bean
    public TransactionManager transactionManager(){
        DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
        transactionManager.setDataSource(dataSource());
        return transactionManager;
    }
    //处理 事务的 方式 有三种
    //第一种最简单的方式，在 RootConfig 加上 @EnableTransactionManagement 注解，再加上配置 DataSourceTransactionManager 的bean，就可以在service实现层使用 @Transactional 注解为方法手动加上事务，并且指定的传播属性等等，但老是要手动加 @Transactional 注解实在麻烦
    //第二种就是文中使用的方式，使用 BeanNameAutoProxyCreator 拦截代理方式，先创建一个 TransactionInterceptor bean，配置好事务传播等属性，在由 BeanNameAutoProxyCreator 进行事务代理。这里有个问题就是 BeanNameAutoProxyCreator 放在 RootConfig 中居然会导致 @value注解获取不到配置文件的值，而是键名字，将它直接放到 RootConfig 下就没事了
    //第三种是采用aop切面事务， @EnableAspectJAutoProxy
    //开启切面自动代理，这里写一个切面相关类 AspectConfig ，然后在 使用 @Import(AspectConfig.class) 导进配置就行，由于 <tx: 开头的这种标签实在不知如何用java方式表示，在 stackoverflow 看到一个答案讲还是只能写一个xml文件，使用 @ImportResource(“classpath:/aop-config.xml”) 这种方式进行配置，具体实现如下(三种方式根据需要去掉无关代码，免得出冲突)

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor(){
        MybatisPlusInterceptor aa=new MybatisPlusInterceptor();
        aa.addInnerInterceptor(new PaginationInnerInterceptor());
        return aa;
    }
}
